#!/bin/bash
#########################################################################
# FRP Client (frpc) Installation Script
# Github: https://github.com/funnyzak/frpc
#
# Description:
#   This script installs, configures, and manages FRP Client (frpc) on Linux systems.
#   It supports multiple configuration methods, customizable paths, and complete management.
#
# Usage:
#   ./frpc.sh [command] [options...]
#
# Commands:
#   install [options]               Install and configure frpc
#   config                          Show current frpc configuration
#   uninstall                       Remove frpc installation
#   tips                            Show usage tips
#   help                            Display help information
#
# Options for install command:
#   --token <value>                 Set the FRP server token (required)
#   --config-url <url>              Download configuration from URL
#   --config-file <path>            Use local configuration file
#   --interactive                   Enter interactive configuration mode
#   --frp-download-url <url>        Custom download URL for frpc package
#   --install-path <path>           Custom installation path
#   --config-path <path>            Custom config file path
#   --version <version>             Specific version to install
#
# Options for uninstall command:
#   --force                         Force uninstallation without confirmation
#
# Environment variables (alternatives to command options):
#   FRPC_INSTALL_PATH               Custom installation path (default: /opt/frpc)
#   FRPC_CONFIG_PATH                Custom config path (default: /etc/frp/frpc.toml)
#   FRPC_DOWNLOAD_URL               Custom download URL for frpc package
#   FRPC_VERSION                    Specific version to install (default: 0.61.2)
#   FRPC_TOKEN                      FRP server token
#
# Examples:
#   # Install with URL configuration:
#   ./frpc.sh install --token my-token-value --config-url http://example.com/frpc.toml
#
#   # Install with local configuration file:
#   ./frpc.sh install --token my-token-value --config-file ./my-frpc.toml
#
#   # Interactive configuration:
#   ./frpc.sh install --token my-token-value --interactive
#
#   # Install with custom paths:
#   ./frpc.sh install --token my-token-value --install-path /usr/local/frpc --config-path /etc/frpc.toml
#
#   # Show current configuration:
#   ./frpc.sh config
#
#   # Show usage tips:
#   ./frpc.sh tips
#
#   # Uninstall frpc:
#   ./frpc.sh uninstall
#
#   # Remote execution example using pipe:
#   curl -sSL https://gitee.com/funnyzak/frpc/raw/main/utilities/shell/frp/frpc.sh | bash -s install --token your_token --config-url http://example.com/frpc.toml
# Author: Leon
# Date: March 27, 2025
#########################################################################

# Enable strict error handling
set -euo pipefail

# Script version
SCRIPT_VERSION="v1.0.0"

# Color definitions
RED="\033[0;31m"
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
BLUE="\033[0;34m"
CYAN="\033[0;36m"
PLAIN="\033[0m"

# Ensure PATH includes standard directories
export PATH=$PATH:/usr/local/bin:/usr/bin:/bin

# Default configuration variables
FRPC_VERSION="${FRPC_VERSION:-0.61.2}"                    # Default frpc version
FRPC_PATH="${FRPC_INSTALL_PATH:-/opt/frpc}"              # Installation directory
FRPC_CONF_PATH="${FRPC_CONFIG_PATH:-/etc/frp/frpc.toml}" # Configuration file path
FRPC_SERVICE_NAME="frpc.service"                         # Systemd service name
FRPC_TOKEN="${FRPC_TOKEN:-}"                             # Server authentication token

# System paths
SERVER_INSTALL_PATH="/etc/systemd/system"                # Systemd service installation path
TMP_PATH="/tmp/frpc_install_$(date +%s)"                 # Temporary directory with timestamp

# Network settings
PROXY_URL="${PROXY_URL:-https://ghfast.top/}"           # GitHub proxy for downloads

# Embedded systemd service config
SYSTEMD_SERVICE_CONTENT=$(cat <<EOF
[Unit]
Description=FRP Client Service
After=network.target
Wants=network-online.target

[Service]
Type=simple
User=root
Restart=on-failure
RestartSec=5s
ExecStart=service_app_install_path/frpc -c service_config_path
LimitNOFILE=1048576

[Install]
WantedBy=multi-user.target
EOF
)

# Default frpc configuration
DEFAULT_FRPC_CONFIG=$(cat <<EOF
# FRP Client Configuration
# Generated by frpc.sh ${SCRIPT_VERSION}
# Date: $(date "+%Y-%m-%d %H:%M:%S")

serverAddr = "your_frps_ip_or_domain"  # Replace with your FRP server IP or domain
serverPort = 7000                      # Replace with your FRP server port (usually 7000)
auth.token = "your_token_here"            # This will be replaced with your token

# Log configuration (optional)
log.level = "info"                     # Log level: trace, debug, info, warn, error
log.maxDays = 3                        # Maximum number of days to keep log files

# TCP proxy example for SSH
[[proxies]]
name = "ssh"                           # Unique name for this proxy
type = "tcp"                           # Protocol type: tcp, udp, http, https, stcp, xtcp
localIP = "127.0.0.1"                  # Local service IP
localPort = 22                         # Local service port (SSH default)
remotePort = 6000                       # Remote port on FRP server for this service

# HTTP proxy example for web service
[[proxies]]
name = "web"                           # Unique name for this proxy
type = "http"                          # Protocol type
localIP = "127.0.0.1"                  # Local service IP
localPort = 80                         # Local port (web default)
customDomains = ["your-domain.com"]    # Your domain bound to this service
EOF
)

#########################################################################
# Helper functions
#########################################################################

# Print a message with a colored prefix
# Usage: log_message TYPE "message"
log_message() {
    local type=$1
    local message=$2
    local color=""
    local prefix=""

    case "$type" in
        "info")
            color="$BLUE"
            prefix="[INFO]"
            ;;
        "success")
            color="$GREEN"
            prefix="[SUCCESS]"
            ;;
        "warning")
            color="$YELLOW"
            prefix="[WARNING]"
            ;;
        "error")
            color="$RED"
            prefix="[ERROR]"
            ;;
        "debug")
            color="$CYAN"
            prefix="[DEBUG]"
            ;;
        *)
            color="$PLAIN"
            prefix="[LOG]"
            ;;
    esac

    echo -e "${color}${prefix}${PLAIN} ${message}"
}

# Display a section header
section_header() {
    echo -e "\n${BLUE}===== $1 =====${PLAIN}"
}

# Confirm an action with user input
# Usage: confirm_action "message" [default]
# Returns: 0 for yes, 1 for no
confirm_action() {
    local message=$1
    local default=${2:-"n"}
    local prompt="[y/n]"

    if [[ "$default" == "y" ]]; then
        prompt="[Y/n]"
    else
        prompt="[y/N]"
    fi

    read -rep "$message $prompt: " response
    response=${response:-$default}

    if [[ "${response,,}" == "y" || "${response,,}" == "yes" ]]; then
        return 0
    else
        return 1
    fi
}

# Escape forward slashes in a string for use in sed
escape_path_for_sed() {
    echo "$1" | sed 's/\//\\\//g'
}

# Parse command line arguments
parse_arguments() {
    if [[ $# -eq 0 ]]; then
        show_help
        exit 0
    fi

    COMMAND=""
    CONFIG_URL=""
    CONFIG_FILE=""
    INTERACTIVE_MODE=false
    FORCE_MODE=false

    # First argument should be a command
    COMMAND="$1"
    shift

    # Handle different commands
    case "$COMMAND" in
        install)
            # Parse install command options
            while [[ $# -gt 0 ]]; do
                case "$1" in
                    --token)
                        if [[ -n "$2" && "$2" != --* ]]; then
                            FRPC_TOKEN="$2"
                            shift 2
                        else
                            log_message "error" "Missing argument for --token option"
                            exit 1
                        fi
                        ;;
                    --config-url)
                        if [[ -n "$2" && "$2" != --* ]]; then
                            CONFIG_URL="$2"
                            shift 2
                        else
                            log_message "error" "Missing argument for --config-url option"
                            exit 1
                        fi
                        ;;
                    --config-file)
                        if [[ -n "$2" && "$2" != --* ]]; then
                            CONFIG_FILE="$2"
                            shift 2
                        else
                            log_message "error" "Missing argument for --config-file option"
                            exit 1
                        fi
                        ;;
                    --interactive)
                        INTERACTIVE_MODE=true
                        shift
                        ;;
                    --frp-download-url)
                        if [[ -n "$2" && "$2" != --* ]]; then
                            FRPC_DOWNLOAD_URL="$2"
                            shift 2
                        else
                            log_message "error" "Missing argument for --frp-download-url option"
                            exit 1
                        fi
                        ;;
                    --install-path)
                        if [[ -n "$2" && "$2" != --* ]]; then
                            FRPC_PATH="$2"
                            shift 2
                        else
                            log_message "error" "Missing argument for --install-path option"
                            exit 1
                        fi
                        ;;
                    --config-path)
                        if [[ -n "$2" && "$2" != --* ]]; then
                            FRPC_CONF_PATH="$2"
                            shift 2
                        else
                            log_message "error" "Missing argument for --config-path option"
                            exit 1
                        fi
                        ;;
                    --version)
                        if [[ -n "$2" && "$2" != --* ]]; then
                            if [[ "$2" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
                                FRPC_VERSION="$2"
                                shift 2
                            else
                                log_message "error" "Invalid version format: $2. Please use a valid version string (e.g., 0.61.2)."
                                exit 1
                            fi
                        else
                            log_message "error" "Missing argument for --version option"
                            exit 1
                        fi
                        ;;
                    *)
                        log_message "error" "Unknown option: $1"
                        show_help
                        exit 1
                        ;;
                esac
            done

            # Validate token is provided for install command
            if [[ -z "$FRPC_TOKEN" ]]; then
                log_message "error" "Token is required for installation. Use --token option or FRPC_TOKEN environment variable."
                exit 1
            fi

            local config_methods=0
            # Count configuration methods selected
            [[ -n "$CONFIG_URL" ]] && config_methods=$((config_methods+1))
            [[ -n "$CONFIG_FILE" ]] && config_methods=$((config_methods+1))
            [[ "$INTERACTIVE_MODE" == true ]] && config_methods=$((config_methods+1))

            # Log the selected configuration method
            if [[ -n "$CONFIG_URL" ]]; then
                log_message "info" "Configuration method: URL (${CONFIG_URL})"
            elif [[ -n "$CONFIG_FILE" ]]; then
                log_message "info" "Configuration method: Local file (${CONFIG_FILE})"
            elif [[ "$INTERACTIVE_MODE" == true ]]; then
                log_message "info" "Configuration method: Interactive setup"
            else
                log_message "info" "Configuration method: Default template"
            fi

            if [[ $config_methods -gt 1 ]]; then
                log_message "error" "Please specify only one configuration method: --config-url, --config-file, or --interactive"
                exit 1
            fi
            ;;
        uninstall)
            # Parse uninstall command options
            while [[ $# -gt 0 ]]; do
                case "$1" in
                    --force)
                        FORCE_MODE=true
                        shift
                        ;;
                    *)
                        log_message "error" "Unknown option: $1"
                        show_help
                        exit 1
                        ;;
                esac
            done
            ;;
        config|help|tips)
            # No additional arguments needed for these commands
            ;;
        *)
            log_message "error" "Unknown command: $COMMAND"
            show_help
            exit 1
            ;;
    esac
}

#########################################################################
# Prerequisite check functions
#########################################################################

# Check if the current user is root
check_root() {
    if [[ $EUID -ne 0 ]]; then
        log_message "error" "This script must be run as root. Please use sudo or switch to root user."
        exit 1
    fi
}

# Check for required commands
check_dependencies() {
    log_message "info" "Checking required dependencies..."

    local missing_deps=()
    local required_commands=("curl" "systemctl" "tar" "grep" "sed")

    for cmd in "${required_commands[@]}"; do
        if ! command -v "$cmd" &>/dev/null; then
            missing_deps+=("$cmd")
        fi
    done

    if [[ ${#missing_deps[@]} -gt 0 ]]; then
        log_message "error" "Missing required dependencies: ${missing_deps[*]}"
        log_message "info" "Please install the missing dependencies and try again."

        # Suggest installation command based on package manager
        if command -v apt-get &>/dev/null; then
            log_message "info" "You can install them using: sudo apt-get update && sudo apt-get install -y ${missing_deps[*]}"
        elif command -v yum &>/dev/null; then
            log_message "info" "You can install them using: sudo yum install -y ${missing_deps[*]}"
        elif command -v dnf &>/dev/null; then
            log_message "info" "You can install them using: sudo dnf install -y ${missing_deps[*]}"
        fi

        exit 1
    fi

    log_message "success" "All dependencies are installed."
}

# Check if systemd is available
check_systemd() {
    if ! command -v systemctl >/dev/null 2>&1; then
        log_message "error" "systemctl command not found. This system does not appear to use systemd."
        exit 1
    fi

    if ! systemctl --version >/dev/null 2>&1; then
        log_message "error" "systemd does not seem to be running on this system."
        exit 1
    fi

    log_message "success" "systemd is available."
}

# Comprehensive pre-installation checks
pre_check() {
    section_header "Pre-installation Checks"
    check_root
    check_dependencies
    check_systemd

    # Create temporary directory
    mkdir -p "${TMP_PATH}"
    log_message "info" "Created temporary directory: ${TMP_PATH}"
}

#########################################################################
# File and download operations
#########################################################################

# Download a file with progress indication
# Usage: download_file URL SAVE_PATH FILENAME DESCRIPTION
download_file() {
    local url="$1"
    local save_path="$2"
    local filename="$3"
    local description="$4"

    if [[ -z "${url}" || -z "${save_path}" || -z "${filename}" ]]; then
        log_message "error" "Incomplete download parameters."
        return 1
    fi

    log_message "info" "Downloading ${description} to ${save_path}/${filename}"
    log_message "info" "Source: ${url}"

    mkdir -p "${save_path}"

    # Validate URL
    if [[ ! "${url}" =~ ^https?:// ]]; then
        log_message "error" "Invalid URL: ${url}. URL must start with http:// or https://"
        return 1
    fi

    # Download with retry and timeout
    if ! curl -o "${save_path}/${filename}" -L --retry 3 --retry-delay 2 --connect-timeout 10 --progress-bar "${url}"; then
        log_message "error" "Failed to download ${description}. Please check your internet connection and the URL."
        return 1
    fi

    if [[ ! -f "${save_path}/${filename}" ]]; then
        log_message "error" "Download completed but file not found: ${save_path}/${filename}"
        return 1
    fi

    log_message "success" "${description} downloaded successfully."
    return 0
}

# Prepare configuration from URL
prepare_config_from_url() {
    local config_url="$1"
    local config_tmp_name="frpc_conf_$(date +%s).toml"

    # Download configuration file
    if ! download_file "${config_url}" "${TMP_PATH}" "${config_tmp_name}" "FRPC configuration"; then
        log_message "error" "Failed to download configuration file from URL: ${config_url}"
        return 1
    fi

    # Store path for later use
    frpc_conf_tmp_path="${TMP_PATH}/${config_tmp_name}"
    log_message "success" "Configuration successfully downloaded from URL."
    return 0
}

# Prepare configuration from local file
prepare_config_from_file() {
    local config_file="$1"

    # Check if file exists and is readable
    if [[ ! -f "${config_file}" ]]; then
        log_message "error" "Configuration file not found: ${config_file}"
        return 1
    fi

    if [[ ! -r "${config_file}" ]]; then
        log_message "error" "Cannot read configuration file: ${config_file}. Check permissions."
        return 1
    fi

    # Copy file to temporary location
    local config_tmp_name="frpc_conf_$(date +%s).toml"
    if ! cp "${config_file}" "${TMP_PATH}/${config_tmp_name}"; then
        log_message "error" "Failed to copy configuration file."
        return 1
    fi

    # Store path for later use
    frpc_conf_tmp_path="${TMP_PATH}/${config_tmp_name}"
    log_message "success" "Configuration successfully loaded from file: ${config_file}"
    return 0
}

# Interactive configuration setup
prepare_interactive_config() {
    local config_tmp_name="frpc_conf_$(date +%s).toml"

    section_header "Interactive Configuration Setup"

    # Initialize with default configuration
    echo "${DEFAULT_FRPC_CONFIG}" > "${TMP_PATH}/${config_tmp_name}"

    echo -e "${YELLOW}Please provide the following information to configure FRPC:${PLAIN}"

    # Server address
    read -rep "Enter FRP server address (IP or domain): " server_addr
    if [[ -z "${server_addr}" ]]; then
        log_message "error" "Server address cannot be empty."
        return 1
    fi

    # Replace the user-entered server address in the configuration file
    sed -i "s/your_frps_ip_or_domain/${server_addr}/g" "${TMP_PATH}/${config_tmp_name}"

    # Server port
    read -rep "Enter FRP server port [7000]: " server_port
    server_port=${server_port:-7000} # Default to 7000 if not provided
    # Validate port number
    if ! [[ "${server_port}" =~ ^[0-9]+$ ]] || [[ "${server_port}" -lt 1 ]] || [[ "${server_port}" -gt 65535 ]]; then
        log_message "error" "Invalid port number. Must be between 1-65535."
        return 1
    fi
    sed -i "s/serverPort = 7000/serverPort = ${server_port}/g" "${TMP_PATH}/${config_tmp_name}"

    # SSH proxy configuration
    echo -e "\n${YELLOW}SSH Proxy Configuration:${PLAIN}"
    read -rep "Do you want to enable SSH proxy? [Y/n]: " enable_ssh
    enable_ssh=${enable_ssh:-y}

    if [[ "${enable_ssh,,}" == "y" || "${enable_ssh,,}" == "yes" ]]; then
        read -rep "Enter local SSH port [22]: " ssh_local_port
        ssh_local_port=${ssh_local_port:-22}
        if ! [[ "${ssh_local_port}" =~ ^[0-9]+$ ]] || [[ "${ssh_local_port}" -lt 1 ]] || [[ "${ssh_local_port}" -gt 65535 ]]; then
            log_message "error" "Invalid port number. Must be between 1-65535."
            return 1
        fi
        sed -i "s/localPort = 22/localPort = ${ssh_local_port}/g" "${TMP_PATH}/${config_tmp_name}"

        read -rep "Enter remote port for SSH on FRP server [6000]: " ssh_remote_port
        ssh_remote_port=${ssh_remote_port:-6000}
        if ! [[ "${ssh_remote_port}" =~ ^[0-9]+$ ]] || [[ "${ssh_remote_port}" -lt 1 ]] || [[ "${ssh_remote_port}" -gt 65535 ]]; then
            log_message "error" "Invalid port number. Must be between 1-65535."
            return 1
        fi
        sed -i "s/remotePort = 6000/remotePort = ${ssh_remote_port}/g" "${TMP_PATH}/${config_tmp_name}"
    else
        # Remove SSH proxy section
        sed -i '/# TCP proxy example for SSH/,/remotePort = 6000/d' "${TMP_PATH}/${config_tmp_name}"
    fi

    # HTTP proxy configuration
    echo -e "\n${YELLOW}HTTP Proxy Configuration:${PLAIN}"
    read -rep "Do you want to enable HTTP proxy? [Y/n]: " enable_http
    enable_http=${enable_http:-y}

    if [[ "${enable_http,,}" == "y" || "${enable_http,,}" == "yes" ]]; then
        read -rep "Enter local HTTP port [80]: " http_local_port
        http_local_port=${http_local_port:-80}
        if ! [[ "${http_local_port}" =~ ^[0-9]+$ ]] || [[ "${http_local_port}" -lt 1 ]] || [[ "${http_local_port}" -gt 65535 ]]; then
            log_message "error" "Invalid port number. Must be between 1-65535."
            return 1
        fi
        sed -i "s/localPort = 80/localPort = ${http_local_port}/g" "${TMP_PATH}/${config_tmp_name}"

        read -rep "Enter domain for HTTP proxy: " http_domain
        if [[ -n "${http_domain}" ]]; then
            sed -i "s/your-domain.com/${http_domain}/g" "${TMP_PATH}/${config_tmp_name}"
        fi
    else
        # Remove HTTP proxy section
        sed -i '/# HTTP proxy example for web service/,/customDomains = \["your-domain.com"\]/d' "${TMP_PATH}/${config_tmp_name}"
    fi

    # Store path for later use
    frpc_conf_tmp_path="${TMP_PATH}/${config_tmp_name}"

    # Preview configuration
    echo -e "\n${YELLOW}Generated Configuration:${PLAIN}"
    echo -e "${GREEN}"
    cat "${frpc_conf_tmp_path}"
    echo -e "${PLAIN}"

    # Confirm configuration
    if ! confirm_action "Is this configuration correct?"; then
        log_message "error" "Configuration cancelled by user."
        return 1
    fi

    log_message "success" "Configuration created successfully."
    return 0
}

# Prepare default configuration
prepare_default_config() {
    local config_tmp_name="frpc_conf_$(date +%s).toml"

    # Create default configuration file
    echo "${DEFAULT_FRPC_CONFIG}" > "${TMP_PATH}/${config_tmp_name}"
    frpc_conf_tmp_path="${TMP_PATH}/${config_tmp_name}"

    log_message "success" "Default configuration created."
    return 0
}

# Apply configuration
apply_frpc_config() {
    if [[ -z "${frpc_conf_tmp_path}" || -z "${FRPC_TOKEN}" ]]; then
        log_message "error" "FRPC configuration file not found or token not set."
        return 1
    fi

    # Create configuration directory if it doesn't exist
    mkdir -p "$(dirname "${FRPC_CONF_PATH}")"

    # Copy configuration file
    cp -f "${frpc_conf_tmp_path}" "${FRPC_CONF_PATH}"

    # Replace token placeholder
    if ! sed -i "s/your_token_here/${FRPC_TOKEN}/g" "${FRPC_CONF_PATH}"; then
        log_message "error" "Failed to set token in configuration file."
        return 1
    fi

    log_message "success" "FRPC configuration applied successfully to ${FRPC_CONF_PATH}"
    return 0
}

#########################################################################
# Installation functions
#########################################################################

# Check for existing installation
check_existing_installation() {
    if [[ -d "${FRPC_PATH}" && -f "${FRPC_CONF_PATH}" && -f "${SERVER_INSTALL_PATH}/${FRPC_SERVICE_NAME}" ]]; then
        log_message "warning" "FRPC is already installed."
        if confirm_action "Do you want to reinstall FRPC?"; then
            return 0
        else
            log_message "info" "Installation canceled by user."
            exit 0
        fi
    fi
    return 0
}

# Detect CPU architecture and set platform variable
detect_cpu_arch() {
    local arch=$(uname -m)
    local platform=""

    case "$arch" in
        x86_64)
            platform="amd64"
            ;;
        aarch64|arm64)
            platform="arm64"
            ;;
        armv7*|armv7l|armhf)
            platform="arm"
            ;;
        *)
            log_message "error" "Unsupported CPU architecture: $arch"
            log_message "info" "This script supports x86_64, aarch64, armv7, armv7l, and armhf architectures."
            exit 1
            ;;
    esac

    echo "$platform"
}

# Check if a URL is accessible
check_url_accessibility() {
    local test_url="$1"

    if curl --connect-timeout 5 --max-time 10 -sI "$test_url" >/dev/null 2>&1; then
        return 0
    else
        return 1
    fi
}

# Get appropriate download URL with fallback options
get_download_url() {
    local version="$1"
    local platform="$2"
    local file_name="frp_${version}_linux_${platform}.tar.gz"
    local github_url="https://github.com/fatedier/frp/releases/download/v${version}/${file_name}"
    local proxy_url="${PROXY_URL}${github_url}"
    local final_url=""

    if check_url_accessibility "https://www.google.com"; then
        final_url="${github_url}"
    else
        final_url="${proxy_url}"
    fi

    echo "${final_url}"
}

# Download and install frpc binary
install_frpc_binary() {
    # Detect CPU architecture
    local platform=$(detect_cpu_arch)

    # Get appropriate download URL
    local download_url=$(get_download_url "${FRPC_VERSION}" "${platform}")

    # Download frpc package
    if ! download_file "${download_url}" "${TMP_PATH}" "frp.tar.gz" "FRPC package"; then
        log_message "error" "Failed to download FRPC package."
        exit 1
    fi

    # Create installation directory
    mkdir -p "${FRPC_PATH}"

    # Extract package
    log_message "info" "Extracting FRPC package..."
    if ! tar -xzf "${TMP_PATH}/frp.tar.gz" -C "${FRPC_PATH}" --strip-components=1; then
        log_message "error" "Failed to extract FRPC package."
        exit 1
    fi

    # Set executable permissions
    chmod +x "${FRPC_PATH}/frpc"

    if [[ ! -f "${FRPC_PATH}/frpc" ]]; then
        log_message "error" "FRPC binary not found after extraction."
        exit 1
    fi

    log_message "success" "FRPC binary installed to ${FRPC_PATH}/frpc"
}

# Configure and install systemd service
setup_systemd_service() {
    local service_content="${SYSTEMD_SERVICE_CONTENT}"

    # Replace paths in service content
    local escaped_app_path=$(escape_path_for_sed "${FRPC_PATH}")
    local escaped_config_path=$(escape_path_for_sed "${FRPC_CONF_PATH}")

    service_content=$(echo "${service_content}" | sed "s/service_app_install_path/${escaped_app_path}/g")
    service_content=$(echo "${service_content}" | sed "s/service_config_path/${escaped_config_path}/g")

    # Write service file
    echo "${service_content}" > "${SERVER_INSTALL_PATH}/${FRPC_SERVICE_NAME}"

    # Validate service file
    if [[ ! -f "${SERVER_INSTALL_PATH}/${FRPC_SERVICE_NAME}" ]]; then
        log_message "error" "Failed to create systemd service file."
        exit 1
    fi

    # Reload systemd, enable and start service
    log_message "info" "Configuring systemd service..."
    systemctl daemon-reload

    if ! systemctl enable "${FRPC_SERVICE_NAME}"; then
        log_message "error" "Failed to enable FRPC service."
        exit 1
    fi

    if ! systemctl restart "${FRPC_SERVICE_NAME}"; then
        log_message "error" "Failed to start FRPC service."
        exit 1
    fi

    # Wait for service to start
    sleep 2

    # Check service status
    log_message "info" "Checking FRPC service status..."
    systemctl status "${FRPC_SERVICE_NAME}" --no-pager

    if ! systemctl is-active "${FRPC_SERVICE_NAME}" &>/dev/null; then
        log_message "warning" "FRPC service is not running. Please check the logs for errors."
        log_message "info" "You can view the logs with: journalctl -u ${FRPC_SERVICE_NAME} -f"
    else
        log_message "success" "FRPC service is running."
    fi
}

# Main installation function
install_frpc() {
    section_header "Installing FRPC"

    # Pre-installation checks
    pre_check

    # Check for existing installation
    check_existing_installation

    # Prepare configuration based on the chosen method
    if [[ -n "${CONFIG_URL}" ]]; then
        prepare_config_from_url "${CONFIG_URL}"
    elif [[ -n "${CONFIG_FILE}" ]]; then
        prepare_config_from_file "${CONFIG_FILE}"
    elif [[ "${INTERACTIVE_MODE}" == true ]]; then
        prepare_interactive_config
    else
        prepare_default_config
    fi

    # Apply configuration
    if ! apply_frpc_config; then
        log_message "error" "Failed to apply FRPC configuration."
        exit 1
    fi

    # Install binary
    install_frpc_binary

    # Setup systemd service
    setup_systemd_service

    # Installation complete
    section_header "Installation Complete"
    log_message "success" "FRPC has been successfully installed and started."
    log_message "info" "Configuration file: ${FRPC_CONF_PATH}"
    log_message "info" "Installation directory: ${FRPC_PATH}"
    log_message "info" "Service name: ${FRPC_SERVICE_NAME}"
    log_message "info" "Management commands:"
    echo "  - Start: sudo systemctl start ${FRPC_SERVICE_NAME}"
    echo "  - Stop: sudo systemctl stop ${FRPC_SERVICE_NAME}"
    echo "  - Restart: sudo systemctl restart ${FRPC_SERVICE_NAME}"
    echo "  - Status: sudo systemctl status ${FRPC_SERVICE_NAME}"
    echo "  - View logs: sudo journalctl -u ${FRPC_SERVICE_NAME} -f"
    echo "  - View config: cat ${FRPC_CONF_PATH}"
}

#########################################################################
# Configuration display function
#########################################################################

show_frpc_config() {
    section_header "FRPC Configuration"

    if [[ ! -f "${FRPC_CONF_PATH}" ]]; then
        log_message "error" "FRPC configuration file ${FRPC_CONF_PATH} does not exist."
        log_message "info" "Please install FRPC first using: $0 install --token your-token-value"
        exit 1
    fi

    # Display general information
    log_message "info" "FRPC Binary Path: ${FRPC_PATH}/frpc"
    log_message "info" "Configuration File: ${FRPC_CONF_PATH}"

    # Check binary and version
    if [[ -f "${FRPC_PATH}/frpc" ]]; then
        local frpc_version=""
        frpc_version=$("${FRPC_PATH}/frpc" -v 2>/dev/null || echo "Unknown")
        log_message "info" "FRPC Version: ${frpc_version}"
    else
        log_message "warning" "FRPC binary not found at ${FRPC_PATH}/frpc"
    fi

    # Service status
    log_message "info" "FRPC Service Status:"
    if systemctl is-active "${FRPC_SERVICE_NAME}" &>/dev/null; then
        echo -e "${GREEN}● Active${PLAIN} - Service is running"

        # Get more detailed status
        local status_output
        status_output=$(systemctl status "${FRPC_SERVICE_NAME}" --no-pager 2>/dev/null)

        # Extract useful information
        local since=$(echo "$status_output" | grep "Active:" | sed -r 's/.*since (.*);.*/\1/g')
        local mem=$(echo "$status_output" | grep "Memory:" | awk '{print $2}')

        if [[ -n "${since}" ]]; then
            log_message "info" "Running since: ${since}"
        fi

        if [[ -n "${mem}" ]]; then
            log_message "info" "Memory usage: ${mem}"
        fi
    else
        echo -e "${RED}● Inactive${PLAIN} - Service is not running"
    fi

    # Display configuration content with line numbers
    log_message "info" "Configuration content:"
    if command -v nl &>/dev/null; then
        echo -e "${GREEN}"
        nl -ba "${FRPC_CONF_PATH}"
        echo -e "${PLAIN}"
    else
        echo -e "${GREEN}"
        cat "${FRPC_CONF_PATH}"
        echo -e "${PLAIN}"
    fi

    # Display connections (if frpc is running)
    if systemctl is-active "${FRPC_SERVICE_NAME}" &>/dev/null; then
        log_message "info" "Recent logs:"
        journalctl -u "${FRPC_SERVICE_NAME}" --no-pager -n 10
    fi
}

#########################################################################
# Uninstallation function
#########################################################################

uninstall_frpc() {
    section_header "Uninstalling FRPC"

    # Check if frpc is installed
    if [[ ! -d "${FRPC_PATH}" && ! -f "${FRPC_CONF_PATH}" && ! -f "${SERVER_INSTALL_PATH}/${FRPC_SERVICE_NAME}" ]]; then
        log_message "warning" "FRPC does not appear to be installed. Nothing to uninstall."
        exit 0
    fi

    # Confirm uninstallation unless force mode is enabled
    if [[ "$FORCE_MODE" != true ]]; then
        log_message "warning" "This will remove FRPC and all its configurations."
        log_message "warning" "All intranet penetration services will be stopped."

        if ! confirm_action "Are you sure you want to uninstall FRPC?"; then
            log_message "info" "Uninstallation canceled by user."
            exit 0
        fi
    else
        log_message "info" "Force mode enabled, skipping confirmation..."
    fi

    # Stop and disable service
    log_message "info" "Stopping and disabling FRPC service..."
    systemctl stop "${FRPC_SERVICE_NAME}" 2>/dev/null || true
    systemctl disable "${FRPC_SERVICE_NAME}" 2>/dev/null || true

    # Remove service file
    if [[ -f "${SERVER_INSTALL_PATH}/${FRPC_SERVICE_NAME}" ]]; then
        rm -f "${SERVER_INSTALL_PATH}/${FRPC_SERVICE_NAME}"
        log_message "info" "Removed service file: ${SERVER_INSTALL_PATH}/${FRPC_SERVICE_NAME}"
    fi

    # Remove configuration file
    if [[ -f "${FRPC_CONF_PATH}" ]]; then
        rm -f "${FRPC_CONF_PATH}"
        log_message "info" "Removed configuration file: ${FRPC_CONF_PATH}"

        # Try to remove configuration directory if empty
        rmdir "$(dirname "${FRPC_CONF_PATH}")" 2>/dev/null || true
    fi

    # Remove installation directory
    if [[ -d "${FRPC_PATH}" ]]; then
        rm -rf "${FRPC_PATH}"
        log_message "info" "Removed installation directory: ${FRPC_PATH}"
    fi

    # Reload systemd
    systemctl daemon-reload
    systemctl reset-failed

    log_message "success" "FRPC has been completely uninstalled."
}

#########################################################################
# Tips display function
#########################################################################

# Display helpful tips and common commands for FRPC
show_frpc_tips() {
    section_header "FRPC Tips and Commands"

    echo -e "${GREEN}┌─────────────────────────────────────────────────────────────┐${PLAIN}"
    echo -e "${GREEN}│               FRPC Service Management Commands              │${PLAIN}"
    echo -e "${GREEN}└─────────────────────────────────────────────────────────────┘${PLAIN}"
    echo

    echo -e "${CYAN}# Service Management:${PLAIN}"
    echo -e "${YELLOW}sudo systemctl start ${FRPC_SERVICE_NAME}${PLAIN}"
    echo -e "  Start frpc service\n"

    echo -e "${YELLOW}sudo systemctl stop ${FRPC_SERVICE_NAME}${PLAIN}"
    echo -e "  Stop frpc service\n"

    echo -e "${YELLOW}sudo systemctl restart ${FRPC_SERVICE_NAME}${PLAIN}"
    echo -e "  Restart frpc service (required after modifying configuration)\n"

    echo -e "${YELLOW}sudo systemctl status ${FRPC_SERVICE_NAME}${PLAIN}"
    echo -e "  Check frpc service status\n"

    echo -e "${YELLOW}sudo systemctl enable ${FRPC_SERVICE_NAME}${PLAIN}"
    echo -e "  Enable frpc service to start on boot\n"

    echo -e "${CYAN}# Log Viewing:${PLAIN}"
    echo -e "${YELLOW}sudo journalctl -u ${FRPC_SERVICE_NAME} -f${PLAIN}"
    echo -e "  View frpc service logs in real-time\n"

    echo -e "${YELLOW}sudo journalctl -u ${FRPC_SERVICE_NAME} --since today${PLAIN}"
    echo -e "  View frpc service logs from today\n"

    echo -e "${CYAN}# Configuration:${PLAIN}"
    echo -e "${YELLOW}cat ${FRPC_CONF_PATH}${PLAIN}"
    echo -e "  View frpc configuration file content\n"

    echo -e "${YELLOW}sudo nano ${FRPC_CONF_PATH}${PLAIN}"
    echo -e "  Edit frpc configuration file (restart service after modification)\n"

    echo -e "${CYAN}# Version & Path Information:${PLAIN}"
    echo -e "${YELLOW}${FRPC_PATH}/frpc -v${PLAIN}"
    echo -e "  View frpc version\n"

    echo -e "${YELLOW}ls -la ${FRPC_PATH}${PLAIN}"
    echo -e "  View content of frpc installation directory\n"

    echo -e "${CYAN}# Network Diagnostics:${PLAIN}"
    echo -e "${YELLOW}sudo lsof -i -P | grep frpc${PLAIN}"
    echo -e "  View network connections opened by frpc\n"

    echo -e "${YELLOW}netstat -tlnp | grep frpc${PLAIN}"
    echo -e "  View frpc listening ports\n"

    echo -e "${GREEN}┌─────────────────────────────────────────────────────────────┐${PLAIN}"
    echo -e "${GREEN}│                 Note: Service Name and Paths                  │${PLAIN}"
    echo -e "${GREEN}└─────────────────────────────────────────────────────────────┘${PLAIN}"
    echo -e "  Service Name: ${YELLOW}${FRPC_SERVICE_NAME}${PLAIN}"
    echo -e "  Config Path: ${YELLOW}${FRPC_CONF_PATH}${PLAIN}"
    echo -e "  Install Path: ${YELLOW}${FRPC_PATH}${PLAIN}"
}

#########################################################################
# Help and cleanup functions
#########################################################################

# Display detailed usage information
show_help() {
    cat <<EOF
$(echo -e "${BLUE}")┌─────────────────────────────────────────────┐$(echo -e "${PLAIN}")
$(echo -e "${BLUE}")│               FRPC Installer                │$(echo -e "${PLAIN}")
$(echo -e "${BLUE}")│               ${SCRIPT_VERSION}             │$(echo -e "${PLAIN}")
$(echo -e "${BLUE}")└─────────────────────────────────────────────┘$(echo -e "${PLAIN}")

FRP Client (frpc) is a tool for intranet penetration.
This script helps install, configure, and manage frpc on your system.

$(echo -e "${YELLOW}")Usage:$(echo -e "${PLAIN}")
  $0 [command] [options...]

$(echo -e "${YELLOW}")Commands:$(echo -e "${PLAIN}")
  install [options]               Install and configure frpc
  config                          Show current frpc configuration
  uninstall [options]             Remove frpc installation
  tips                            Show helpful tips and commands
  help                            Display this help information

$(echo -e "${YELLOW}")Options for install command:$(echo -e "${PLAIN}")
  --token <value>                 Set the FRP server token (required)
  --config-url <url>              Download configuration from URL
  --config-file <path>            Use local configuration file
  --interactive                   Enter interactive configuration mode
  --frp-download-url <url>        Custom download URL for frpc package
  --install-path <path>           Custom installation path
  --config-path <path>            Custom config file path
  --version <version>             Specific version to install

$(echo -e "${YELLOW}")Options for uninstall command:$(echo -e "${PLAIN}")
  --force                         Force uninstallation without confirmation

$(echo -e "${YELLOW}")Environment variables (alternatives to command options):$(echo -e "${PLAIN}")
  FRPC_INSTALL_PATH               Custom installation path (default: /opt/frpc)
  FRPC_CONFIG_PATH                Custom config path (default: /etc/frp/frpc.toml)
  FRPC_DOWNLOAD_URL               Custom download URL for frpc package
  FRPC_VERSION                    Specific version to install (default: ${FRPC_VERSION})
  FRPC_TOKEN                      FRP server token
  PROXY_URL                       Proxy URL for downloading (default: ${PROXY_URL})
  SERVER_INSTALL_PATH             Systemd service file path (default: /etc/systemd/system)
  SERVER_INSTALL_NAME             Systemd service name (default: ${FRPC_SERVICE_NAME})
  TMP_PATH                        Temporary directory for downloads (default: /tmp/frpc_install)
  FRPC_SERVICE_NAME              Systemd service name (default: ${FRPC_SERVICE_NAME})

$(echo -e "${YELLOW}")Examples:$(echo -e "${PLAIN}")
  # Install with URL configuration:
  $0 install --token my-token-value --config-url http://example.com/frpc.toml

  # Install with local configuration file:
  $0 install --token my-token-value --config-file ./my-frpc.toml

  # Interactive configuration:
  $0 install --token my-token-value --interactive

  # Install with custom paths:
  $0 install --token my-token-value --install-path /usr/local/frpc --config-path /etc/frpc.toml

  # Show current configuration:
  $0 config

  # Uninstall frpc with confirmation:
  $0 uninstall

  # Force uninstall without confirmation:
  $0 uninstall --force
EOF
}

# Clean up temporary files
clean_tmp() {
    if [[ -d "${TMP_PATH}" ]]; then
        rm -rf "${TMP_PATH}"
        log_message "info" "Cleaned up temporary files."
    fi
}

########################################################################
# Main script execution
########################################################################

# Trap for cleanup
trap clean_tmp EXIT

# Parse command line arguments
parse_arguments "$@"

# Execute requested command
case "${COMMAND}" in
    install)
        install_frpc
        ;;
    config)
        show_frpc_config
        ;;
    uninstall)
        uninstall_frpc
        ;;
    help)
        show_help
        ;;
    tips)
        show_frpc_tips
        ;;
    *)
        show_help
        exit 1
        ;;
esac

exit 0
